//
//  ST_MediaChatDispatcher.swift
//  btvideo
//
//  Created by mac on 2020/12/10.
//  Copyright © 2020 JarvanZhang. All rights reserved.
//

import UIKit
import NIMSDK
import SwiftyJSON
import SwiftyAttributes
import SwiftyUserDefaults

/**
 ST_TIANEngagementManager.defaultManager.engagement_entiy
 每次聊天会单独创建一个 engagement_entiy ，它里面很多通话相关属性，New()避免了 跟上一个相关联的情况bug之类的。
 每次通话结束 set 为 nil
 */

///  上墙的用户 ，接受邀请
class ST_MediaChatDispatcher: NSObject {
    
    
    //MARK: - init
    static let shared = ST_MediaChatDispatcher()
    
    /// 当前加入频道或者接受频道 请求中
    private var isRequesting = false
    /** 当前正在聊的accid
     */
    var chat_p2_p_session_id:String?
    
    /**
     邀请的弹窗 accid
     */
    var live_alert_accid_set = Set<String>()
    /**
     我的邀请
     */
    weak var inviting_controller:UIViewController?
    
    /**
     接受邀请
     */
    weak var received_controller:UIViewController?
    
    /**
     匹配中动画
     */
    weak var matching_animate_controller:UIViewController?
    
    fileprivate var player:AVAudioPlayer?
    
    private override init() {
        super.init()
    }
    
    
    //    MARK: - Private Method
    
    
    
    /**
     是否允许 跳转
     */
    fileprivate func check_can_presentlogic()->Bool{
        
        if inviting_controller == nil && received_controller == nil  && ST_TIANEngagementManager.defaultManager.engagement_entiy == nil{
            return true
        }
        return false
        
    }
    
    
    ///  自动加入聊天 事件
    fileprivate func auto_join_chat_event(json:JSON,isVideo:Bool){
        
        guard let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else { return  }
        
        if ArrestChatLine(isVideo:isVideo){
            
            ST_MaidWayManager.shared.source = isVideo ? .语音冲币 :  .视频冲币
            
            ST_RechargeViewController.toast()
            
            return
        }
        
        
        
        if user.sex == .female && FACE_AVATAE_STATE != 3{
            
            
            ToastDetectFaceTips(vcCreater: nil)
            
            return
            
        }
        
        if !check_can_presentlogic(){
            
            self.push_cancel_another_invite(accid: json["accid"].stringValue, isVideo: isVideo, text: "对方忙线",stopVoice: false)
            
            return
        }
        
//        let channel = json["channel_name"].stringValue
        print("接受视频配对pushed data:",json)
        
        let entity = ST_TIANEngagementEntiy(chatType: isVideo ? .video : .voice, joinConfig: json, pushPathStr: "接受邀请", isReceived: true)
        
        
        self.received_controller = ST_TIANEngagementManager.defaultManager.startEngine(engineParam: entity)
        
    }
    
    fileprivate func authorization_video_tips_handle(){
        
        
        let titleStr = "需要开启摄像头权限".withAttributes([Attribute.textColor(Color.init(red: 51, green: 51, blue: 51)!),Attribute.font(Font.systemFont(ofSize: 18, weight: UIFont.Weight.medium))])
        
        
        let style = NSMutableParagraphStyle()
        style.alignment = .center
        style.lineSpacing = 5
        
        let content_string = "通话需要访问你的摄像头\n立即前往开启？".withAttributes([Attribute.textColor(Color.init(red: 97, green: 102, blue: 111)!),Attribute.font(Font.systemFont(ofSize: 14, weight: UIFont.Weight.regular)),Attribute.paragraphStyle(style)])
        
        let alert = ST_BTAlertViewController.init(title: titleStr, message: content_string, imageName: "首页_icon_提示",cancelText:"稍后再说")
        
        alert.root_view_height = 290;
        
        alert.overCurrentContext = true;
        
        
        
        alert.confirm_closure = {
            
            PushTianSetting()
        }
        
        GlobalPresent(toController: alert)
        
    }
    
    
    fileprivate func authorization_voice_tips_handle(){
        
        
        let titleStr = "需要开启麦克风权限".withAttributes([Attribute.textColor(Color.init(red: 51, green: 51, blue: 51)!),Attribute.font(Font.systemFont(ofSize: 18, weight: UIFont.Weight.medium))])
        
        
        let style = NSMutableParagraphStyle()
        style.alignment = .center
        style.lineSpacing = 5
        
        let content_string = "通话需要访问你的麦克风\n立即前往开启？".withAttributes([Attribute.textColor(Color.init(red: 97, green: 102, blue: 111)!),Attribute.font(Font.systemFont(ofSize: 14, weight: UIFont.Weight.regular)),Attribute.paragraphStyle(style)])
        
        let alert = ST_BTAlertViewController.init(title: titleStr, message: content_string, imageName: "首页_icon_提示",cancelText:"稍后再说")
        
        alert.root_view_height = 290;
        
        alert.overCurrentContext = true;
        
        
        
        alert.confirm_closure = {
            
            PushTianSetting()
        }
        
        GlobalPresent(toController: alert)
        
    }
    
    
    
    
    //    MARK: - Public Method
    
    /**
     接受 加入 频道
     */
    func apply_join_received_invite(json:JSON,isVideo:Bool){
        
        /// 多了权限判断
        if isVideo{
            
            ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
                
                self.auto_join_chat_event(json: json, isVideo: isVideo)
            }
            
        }else{
            
            ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
                
                ST_MediaChatDispatcher.shared.request_video_permission_with_execute {
                    
                    self.auto_join_chat_event(json: json, isVideo: isVideo)
                }
            }
        }
    }
    
    ///  匹配语音通话 按钮 事件，因为全局有多个按钮同一个事件，所以统一处理
    @objc func match_voice_handle(sender:UIControl){
      
        ST_BTUserInfoManager.shared.judge_account_frozen().withUnretained(self).subscribe(onNext: { own,_ in
            
            own.start_match_voice(sender: sender)
            
        }).disposed(by: rx.disposeBag)
        
        
        
    }
    
    /// 开始匹配  跟 上墙挂钩 , 退出来还是上墙状态，别人邀请我，我就 auto_join_chat_event  自动接听
    private func start_match_voice(sender:UIControl){
        
        ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
            
            
            ST_LiveBeautyWidget.shared.settingUpLiveSquare(isVideo: false, fromController: sender.parentViewController,themeId:nil,sign: nil).subscribe(onNext: { f in
                
                if !f { return }
                
                if (sender.parentViewController is ST_WaitChatRankViewController) == false{
                 
                    GlobalPresent(toController: ST_VoiceChatMatchingAnimateViewController())
                }
                
                
            }).disposed(by: ST_BTLaunchController.shared.rx.disposeBag)
            
        }
        
    }
    
    @objc func match_video_handle(sender:UIControl){
        
        
        ST_BTUserInfoManager.shared.judge_account_frozen().withUnretained(self).subscribe(onNext: { own,_ in
            
            own.start_video_voice(sender: sender)
            
        }).disposed(by: rx.disposeBag)
        
        
    }
    
    private func start_video_voice(sender:UIControl){
        
        ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
            
            ST_MediaChatDispatcher.shared.request_video_permission_with_execute {
             
                  
                ST_LiveBeautyWidget.shared.settingUpLiveSquare(isVideo: true, fromController: sender.parentViewController,themeId:nil,sign: nil).subscribe(onNext: { f in
                    
                    if !f { return }
                    
                    if (sender.parentViewController is ST_WaitChatRankViewController) == false{
                     
                        GlobalPresent(toController: ST_VideoChatMatchingAnimateViewController())
                    }
                    
                    
                }).disposed(by: ST_BTLaunchController.shared.rx.disposeBag)
                
            }
        }
        
    }
    
    
    
//    "聊天速配"
    @objc  func match_peculiarity_handle(){
        
        
        if ownPeculiarityCount < 1{
            
            let vc = BTVerticalAlertViewController.createPpNoOwnPecAlert()
            
            
            vc.confirm_closure = {
                
                push_to_push_peculiarity_controller(navigationController: nil)
                
            }
            
            GlobalPresent(toController: vc)
            
            return
        }
        
        let optionVC = ST_MatchBeforeOptionsController()
        
        optionVC.overCurrentContext = true
        
        GlobalPresent(toController: optionVC)
        
        
    }
    
    
    /// 取消邀请 &&  talkCancel 接口
    func cancel_invite_chat(sessionId:String,isVideo:Bool)  {
        
        if self.inviting_controller == nil{
            return
        }
        
        push_cancel_another_invite(accid: sessionId, isVideo: isVideo,text: "对方已挂断聊天结束")
        
        
    }
    
    
    /// 添加 通话记录📝 type 1语音 2 视频  不是自定义消息的聊天记录 这个是通话记录列表页
    func append_call_history(targetAccid:String,type:Int,duration:Int = 0){
        
//        if self.inviting_controller == nil{
//            return
//        }
        
        var param = ["target_accid":targetAccid,"resource_type":type.string]
        
        
        if duration > 0{
            param.updateValue(duration.string, forKey: "duration")
            param.updateValue("2", forKey: "type")
        }else{
            param.updateValue("1", forKey: "type")
        }
    
        
        
    
        JVrequest(PH.appendRecentCallApi,parameters: param) { json in
            
            print("【通话记录调试】 finished");
            
        } failure: { code, err in
            
            print("【通话记录调试】error:",err)
        }

    }
    
    ///talkCancel 接口  会推送 voice_match_cancel 类似
    func push_cancel_another_invite(accid:String,isVideo:Bool,text:String = "",stopVoice:Bool = true){
        
        if stopVoice{
            stop_waiting_voice()
        }
        
        let resultStr = "------------------\(Date())\n " + PH.cancelInviteChatApi + "--text:" + text + "type:" + isVideo.string
        
        print(resultStr, to: &todayMatchingLogger)
        
        JVrequest(PH.cancelInviteChatApi,parameters: ["target_accid":accid,"text":text,"type":(isVideo ? "2" : "1")]) { (json) in
            
            print("[ST_MediaChatDispatcher] — 取消邀请聊天,",json)
            
        } failure: { (code, err) in
            
            print("[ST_MediaChatDispatcher] — 取消邀请聊天错误：",err)
        }
        
    }
    
    /// 外部分配过来 处理 这个类相关的 逻辑
    func recive_invite_system_message(messages:[NIMMessage]){
        
        
        if Defaults[.isPanda] { return }
        
        //        邀请方 key = sessionId  value = json
        var inviteOperMap = [String:JSON]()
        
        for message in messages {
            
            if Date(timeIntervalSince1970: message.timestamp) < ST_DTBootManager.shared.bootDate{
                
                let resultStr = "------------------\(Date())\n 消息是没有在线的时候 发的"
                
                print(resultStr, to: &todayMatchingLogger)
                
                continue
            }
            
            var remoteJson:JSON?
            
            if let text = message.text {
                let k = JSON(parseJSON: text)
                if k.type != .null {
                    remoteJson = k;
                }
            }
            
            if remoteJson == nil{
                if let remoteExt = message.remoteExt{
                    remoteJson = JSON.init(remoteExt)
                }
            }
            
            guard let json = remoteJson else { return  }
            
                        print("[ST_MediaChatDispatcher] — 收到的邀请数据:",json)
            
//            let resultStr = "------------------\(Date())\n 收到的邀请数据:" + (json.rawString() ?? "")
            
//            print(resultStr, to: &todayMatchingLogger)
            
            let anotherAccid = json["data"]["from_accid"].stringValue
            
            
            if anotherAccid == ST_BTUserInfoManager.shared.current_account_info?.accid {
                
                print("[ST_MediaChatDispatcher] — 推自己bug:",json)
                
                let resultStr = "------------------\(Date())\n 上面是推自己bug"
                
                print(resultStr, to: &todayMatchingLogger)
                
                continue
            }
            
            switch json["type"].stringValue {
            case "wy_video_match_success","wy_voice_match_success":
                inviteOperMap.updateValue(json, forKey: anotherAccid)
            case "wy_voice_match","wy_video_match":
                inviteOperMap.updateValue(json, forKey: anotherAccid)
            case "wy_voice_match_cancel","wy_video_match_cancel":
                
                let agoraType = json["type"].stringValue == "voice_match_cancel" ? 1 : 2
                
                
//
//                self.appendNotConnectedHistory(targetAccid: anotherAccid, type: agoraType)
                
                
                //                如果是在我邀请中，则是拒绝我的通话
                if ST_BTUserInfoManager.shared.app_chat_status_behavior.value.rawValue == ST_TIAN_MEDIA_SATE_ENUM.invitingP2P.rawValue, anotherAccid == self.chat_p2_p_session_id{
                    //                    self.status = .leisure
                    ST_BTUserInfoManager.shared.revert_last_status()
                    
                    self.chat_p2_p_session_id = nil
                    
                    
                    let reason = json["data"]["msg"].stringValue
                    
                    if let objc = self.inviting_controller as? ST_RefuseMediaInviteProtocol{
                        objc.refuseMe(text: reason)
                    }
                    
                    
                    
                    if reason.contains("拒绝") {
                        
                        print("【通话记录】- 拒绝我的邀请")
                        
                        ST_DTChatFeed.shared.sendCallRecord(sessionId: anotherAccid, agoraType: agoraType, recordtype: ST_TIANRecordType.refuse)
                        
                    }else if reason.contains("忙") {
                        
                        print("【通话记录】- 拒绝我 对方忙")
                        
                        ST_DTChatFeed.shared.sendCallRecord(sessionId: anotherAccid, agoraType: agoraType, recordtype: ST_TIANRecordType.busy)
                    }
                }
                
                //                邀请又拒绝
                self.live_alert_accid_set.remove(anotherAccid)
                
                /*
                 //                邀请我，但是又取消
                 if ST_LiveBeautyWidget.shared.status == .waitingRespP2P, anotherAccid == self.chat_p2_p_session_id{
                 //                    self.status = .leisure
                 
                 ST_LiveBeautyWidget.shared.revert_last_status()
                 
                 self.chat_p2_p_session_id = nil
                 
                 stop_waiting_voice()
                 
                 self.answerController?.cancelInvite()
                 
                 }
                 */
                
                //                抵消 发起的通话
                inviteOperMap.removeValue(forKey: anotherAccid)
            default:
                break
            }
        }
        
        for item in inviteOperMap {
            
            let isVideo = item.value["type"].stringValue.contains("video")
            
            //            我不是 空闲
            if ST_BTUserInfoManager.shared.app_chat_status_behavior.value.rawValue > 2 {
                
                self.push_cancel_another_invite(accid: item.key, isVideo: isVideo, text: "对方忙线",stopVoice: false)
                
                return
            }
            
            var result = item.value["data"]
            
            result["type"] = isVideo ? "2" : "1"
            
            if !check_can_presentlogic(){
                
                self.push_cancel_another_invite(accid: result["from_accid"].stringValue, isVideo: isVideo, text: "对方忙线",stopVoice: false)
                
                return
            }
            
            
            main_thread_execute {
                
                //            判断直接进频道 上墙的用户，和匹配的用户
                if item.value["type"].stringValue.contains("success") || item.value["data"]["invite_distract"].stringValue == "upLiveWall" {
                    
                    if UIApplication.shared.applicationState == .active{
                        //                        自己在匹配中 才强制进
                        switch  ST_BTUserInfoManager.shared.app_chat_status_behavior.value {
                        case .fallInVoiceQueue,.fallInVideoQueue:
                            if let animateVC = self.matching_animate_controller{
                                
                                animateVC.goback_previous_controller(animated: false) {
                                    
                                    self.apply_join_received_invite(json: result, isVideo: isVideo)
                                    
                                }
                                
                            }else{
                                self.apply_join_received_invite(json: result, isVideo: isVideo)
                            }
                            return
                        default:
                            return
                        }
                    }
                    
                }
                var cupid = TalkCupidViewType._PrivateConversation
                
                if item.value["type"].stringValue.contains("success"){
                    cupid = TalkCupidViewType.matchedConversation
                }
                
                self.toastCupid(result: result,cupidType:cupid)
                
            }
            
        }
        
    }
    
    
    /**
     require execute in cupid
     */
    fileprivate func toastCupid(result:JSON,cupidType:TalkCupidViewType){
        
        self.live_alert_accid_set.update(with: result["accid"].stringValue)
        
        let vc = CupidFactory.currency(for: result, cupidType: cupidType)
        
        GlobalPresent(toController: vc)
        
    }
    
    
    func inviteChat(sessionId:String,isVideo:Bool,inviteDistract:String = "")  {
        
        if ST_TIANEngagementManager.defaultManager.engagement_entiy != nil {
        
            TopmostViewController()?.toast(text: "正在通话，请稍后再试")
            
            return
        }
        
        
        if isVideo{
            
            ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
                
                ST_MediaChatDispatcher.shared.request_video_permission_with_execute {
                    
                    self.invite_chat_execute(sessionId: sessionId, isVideo: isVideo,inviteDistract: inviteDistract)
                }
            }
            
        }else{
            
            ST_MediaChatDispatcher.shared.request_audio_permission_with_execute {
//                ST_MediaChatDispatcher.shared.request_video_permission_with_execute {
                    self.invite_chat_execute(sessionId: sessionId, isVideo: isVideo,inviteDistract: inviteDistract)
//                }
            }
        }
    }
    
    fileprivate func invite_chat_execute(sessionId:String,isVideo:Bool,inviteDistract:String = ""){
        
        if ArrestChatLine(isVideo:isVideo){
            
            ST_MaidWayManager.shared.source = isVideo ? .语音冲币 :  .视频冲币
            
            ST_RechargeViewController.toast()
            
            return
        }
        
        guard let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else{
            
            return
        }
        
        
        if user.sex == .female && FACE_AVATAE_STATE != 3{
            
            
            ToastDetectFaceTips(vcCreater: nil)
            
            
            return
            
        }
        
        let upLiveWall = inviteDistract == "upLiveWall"
        
        var api = upLiveWall ? PH.alternativeEngagementPrivateVideoApi : PH.EngagementPrivateVideoApi
        
        if !isVideo{
            api = upLiveWall ? PH.alternativeEngagementPrivateVoiceApi : PH.EngagementPrivateVoiceApi
        }
        
        let paramters = ["target_accid":sessionId,"invite_distract":inviteDistract]
        
        let resultStr = "------------------\(Date())\n api=" + api + "--param:" + String(describing: paramters)
        
        print(resultStr, to: &todayMatchingLogger)
        
        if isRequesting{
            return
        }
        
        isRequesting = true
        
        JVrequest(api,parameters: paramters) { (json) in
            
            
            self.isRequesting = false
            
            if !self.check_can_presentlogic() {
                
                return
            }
            
            ST_BTUserInfoManager.shared.updateapp_chat_status(value: .invitingP2P)
            
            self.chat_p2_p_session_id = sessionId
            
            
            let entity = ST_TIANEngagementEntiy(chatType: isVideo ? .video : .voice, joinConfig: json["data"], pushPathStr: "邀请聊天")
            
            self.inviting_controller =  ST_TIANEngagementManager.defaultManager.startEngine(engineParam: entity)
            
            
            
        } failure: { (code, err) in
            
            if err.contains("甜心币不足"){
                
                NotificationCenter.default.post(name: ST_LiveBeautyWidget.delete_live_queue_notification, object: nil, userInfo: ["accid":sessionId])
            }
            
            TopmostViewController()?.toast(text: err)
            
            self.isRequesting = false
            
        }
        
    }
    
    /// 取消上墙
    func cancel_talk_matching(){
        
        ST_BTUserInfoManager.shared.revert_last_status()
        
        //        stop_waiting_voice()
    }
    
    
    /// 记录跟谁在聊天
    func talk_p2_p(sessionId:String){
        
        ST_BTUserInfoManager.shared.updateapp_chat_status(value: .talkingP2P)
        
        self.chat_p2_p_session_id = sessionId
        
        //        stop_waiting_voice()
    }
    
    func hung_up_p2_p(sessionId:String){
        
        //            ST_LiveBeautyWidget.shared.revert_last_status()
        
        self.chat_p2_p_session_id = nil
        
    }
    
    func play_waiting_voice()  {
        
        //        try? AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
        if self.player != nil{
            return
        }
        let url = Bundle.main.url(forResource: "call", withExtension: "mp3")
        player = try! AVAudioPlayer(contentsOf: url!)
        player?.numberOfLoops =  -1 // set your count here
        player?.volume = 1
        player?.play()
    }
    
    
    func stop_waiting_voice()  {
        self.player?.stop()
        self.player = nil
    }
    
    
    func request_audio_permission_with_execute( block: @escaping (()->())){
        
        switch AVCaptureDevice.authorizationStatus(for: AVMediaType.audio) {
        case .denied,.restricted:
            authorization_voice_tips_handle()
            break
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: AVMediaType.audio) { (f) in
                if f{
                    main_thread_execute {
                        block()
                    }
                }
            }
            break
        default:
            block()
        }
        
        
        
    }
    
    
    func request_video_permission_with_execute(block: @escaping (()->())){
        
        switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) {
        case .denied,.restricted:
            authorization_video_tips_handle()
            break
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: AVMediaType.video) { (f) in
                if f{
                    main_thread_execute {
                        block()
                    }
                }
            }
            break
        default:
            block()
        }
    }
    
}




//MARK: - protocol
protocol ST_RefuseMediaInviteProtocol {
    func refuseMe(text:String)
}
